package com.socio.activities;

import java.util.Hashtable;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnFocusChangeListener;
import android.view.View.OnKeyListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;

import com.google.gson.Gson;
import com.socio.model.ClientUser;
import com.socio.threads.BackendThread;
import com.socio.threads.BackendThread.BackendThreadMessages;
import com.socio.threads.BackendThread.BackendThreadModes;

public class SocioSettings extends Activity {

	// different types of dialogs
	static final int SETTINGS_PROGRESS_DIALOG = 0;
	static final int TROUBLE_GETTING_SETTINGS = 1;
	static final int NO_NICKNAME_DIALOG = 2;
	static final int NICKNAME_TOO_LONG = 3;
	static final int SUBMIT_SUCCESSFUL_DIALOG = 4;
	static final int OKAY_WITH_FACEBOOK = 5;
	static final int CANCEL_FACEBOOK_DIALOG = 6;
	
	// view components
	private EditText nickname;
	private CheckBox facebookCheckbox;
	private Button saveButton;
	
	private InputMethodManager softKeyboard;
	private TelephonyManager telephonyManager;
	
	private ClientUser display;
	
	// Define the Handler that receives messages from the search thread and update the progress
    final Handler handler = new Handler() { public void handleMessage(Message msg) { handleBackendThreadMessage(msg);}};
	
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
	    super.onCreate(savedInstanceState);
	    setContentView(R.layout.settings);
	    
	    nickname = (EditText)findViewById(R.id.Nickname);
	    facebookCheckbox = (CheckBox)findViewById(R.id.FacebookNetworkCheckBox);
	    saveButton = (Button)findViewById(R.id.SaveButton);
	    
	    // get system services
		softKeyboard = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
	    telephonyManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
	    
	    // input key listener
	    nickname.setOnKeyListener(new OnKeyListener() {
			public boolean onKey(View v, int keyCode, KeyEvent event) {
				
				// When Enter is pressed focus on next input field
				if ((event.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {
					softKeyboard.hideSoftInputFromWindow(v.getWindowToken(), 0);
					saveButton.requestFocus();
					return true;
				}
				return false;
			}
		});
	    
	    // input change listener
	    nickname.setOnFocusChangeListener(new OnFocusChangeListener() {
			public void onFocusChange(View v, boolean hasFocus) {

				// if gets focus and default string is there, remove it and set text to black
				if (hasFocus && ((EditText) v).getText().toString().
						equalsIgnoreCase(getResources().getString(R.string.nickname_default_text))) {
					nickname.setText("", TextView.BufferType.EDITABLE);
					nickname.setTextColor(Color.BLACK);
				}
			}
		});
	    
	    // save and submit nickname when save button is clicked
	    saveButton.setOnClickListener(new OnClickListener() { public void onClick(View v) { submitNickname(); }});
	    
	    // send a user to authorize Socio is checkbox is clicked
	    facebookCheckbox.setOnClickListener(new OnClickListener() { public void onClick(View v) { toggleFacebook(); }});
	    
	    // re-create saved state
	    if(savedInstanceState != null) {
	    	ClientUser user = (ClientUser)savedInstanceState.getSerializable("display");
	    	displaySettings(user, false);
	    } else {
	    	getSettings();
	    }
	}
	
	/**
	 * Handle checking and unchecking of Facebook checkbox
	 */
	private void toggleFacebook() {
		
		facebookCheckbox.toggle();
		boolean facebookChecked = facebookCheckbox.isChecked();
		
		if(!facebookChecked)
			showDialog(OKAY_WITH_FACEBOOK);
		else
			showDialog(CANCEL_FACEBOOK_DIALOG);
	}
	
	/**
	 * Gets a users' settings from web
	 */
	private void getSettings() {
		showDialog(SETTINGS_PROGRESS_DIALOG);
		
		// get params
		String udid = telephonyManager.getDeviceId();
		Hashtable<String,Object> extraParams = new Hashtable<String, Object>();
        Uri.Builder uriBuilder = new Uri.Builder();
		uriBuilder = uriBuilder.encodedPath(getResources().getString(R.string.socio_prod_host) + "resources/settings/get").
		appendQueryParameter("udid", udid);
		extraParams.put("uriBuilder", uriBuilder);
		BackendThread thread = new BackendThread(handler, BackendThreadModes.GetSettings, extraParams);
		thread.start();
	}
	
	/**
	 * Submit new nickname for user
	 */
	private void submitNickname() {
		if(!isValidNickname())
			return;
		
		ClientUser user = new ClientUser();
		user.setUdid(telephonyManager.getDeviceId());
		user.setNickname(nickname.getText().toString());
		
		Gson gson = new Gson();
		String json = gson.toJson(user);
		
		Hashtable<String,Object> extraParams = new Hashtable<String, Object>();
		Uri.Builder uriBuilder = new Uri.Builder();
		uriBuilder = uriBuilder.encodedPath(getResources().getString(R.string.socio_prod_host) + "resources/settings/post");
		extraParams.put("uriBuilder", uriBuilder);
		extraParams.put("json", json);
		
		// start up thread 
		BackendThread thread = new BackendThread(handler, BackendThreadModes.SubmitNickname, extraParams);
		thread.start();
	}
	
	/**
	 * Validate user's proposed nickname
	 * 
	 * @return if nickname is valid
	 */
	private boolean isValidNickname() {
		if(nickname.getText().toString().length() < 1 || nickname.getTextColors().getDefaultColor() == Color.LTGRAY) {
			showDialog(NO_NICKNAME_DIALOG);
			return false;
		}
		
		if(nickname.getText().toString().length() > 8) {
			showDialog(NICKNAME_TOO_LONG);
			return false;
		}
		
		return true;
	}
	
	/**
	 * Displays a user's settings
	 * @param user user with settings to display
	 * @param isSearchDialogUp was the search dialog called before this method
	 */
	private void displaySettings(ClientUser user, boolean isSearchDialogUp) {
		
		display = user;
		
		// process nickname
		String userNickname = user.getNickname();
		if(userNickname.length() != 0) {
			nickname.setText(userNickname, TextView.BufferType.EDITABLE);
			nickname.setTextColor(Color.BLACK);
		}
		
		// handle network enables
		if(user.hasFacebookID())
			facebookCheckbox.setChecked(true);
		else
			facebookCheckbox.setChecked(false);
		
		if(isSearchDialogUp)
			dismissDialog(SETTINGS_PROGRESS_DIALOG);
	}
	
	/**
	 * Semds user to facebook via the browser to authorize Socio
	 */
	private void sendToFacebook() {
		String url = "https://graph.facebook.com/oauth/authorize?client_id=135216369868379" +
				"&redirect_uri=http://socioapp1.appspot.com/resources/oauth/redirect?udid=" +
				telephonyManager.getDeviceId();
		
		Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
		startActivity(intent);
	}
	
	/**
	 * Creates dialogs
	 */
	@Override
	protected Dialog onCreateDialog(int id) {
		Dialog dialog = null;
		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		switch (id) {
		case SETTINGS_PROGRESS_DIALOG:
			ProgressDialog progressDialog = new ProgressDialog(this);
			progressDialog.setMessage("Getting your settings. Please wait...");
			progressDialog.setCancelable(false);
			dialog = progressDialog;
			break;
		case TROUBLE_GETTING_SETTINGS:
			// build alert dialog with error message and ok button
			builder.setMessage("Trouble getting your settings. Please try again")
		       .setCancelable(false)
		       .setNeutralButton("Ok", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(TROUBLE_GETTING_SETTINGS);
		           }
		       });
			dialog = builder.create();
			break;
		case NO_NICKNAME_DIALOG:
			// build alert dialog with error message and ok button
			builder.setMessage("You must enter a nickname to identify yourself to other users.")
		       .setCancelable(false)
		       .setNeutralButton("Ok", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(NO_NICKNAME_DIALOG);
		        	   nickname.requestFocus();
		           }
		       });
			dialog = builder.create();
			break;
		case NICKNAME_TOO_LONG:
			// build alert dialog with error message and ok button
			builder.setMessage("Your nickname can be at most 8 characters long.")
		       .setCancelable(false)
		       .setNeutralButton("Ok", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(NICKNAME_TOO_LONG);
		        	   nickname.requestFocus();
		           }
		       });
			dialog = builder.create();
			break;
		case SUBMIT_SUCCESSFUL_DIALOG:
			// build alert dialog with error message and ok button
			builder.setMessage("Your settings have been changed.")
		       .setCancelable(false)
		       .setNeutralButton("Ok", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(SUBMIT_SUCCESSFUL_DIALOG);
		           }
		       });
			dialog = builder.create();
			break;
		case OKAY_WITH_FACEBOOK:
			// build alert dialog with error message and ok button
			builder.setMessage("You are about to be taken away from this app to authorize Socio through Facebook." +
					" Is this ok?")
		       .setCancelable(false)
		       .setNegativeButton("No", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(OKAY_WITH_FACEBOOK);
		           }
		       }).setPositiveButton("Authorize Socio", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(OKAY_WITH_FACEBOOK);
		        	   sendToFacebook();
		           }
		       });
			dialog = builder.create();
			break;
		case CANCEL_FACEBOOK_DIALOG:
			// build alert dialog with error message and ok button
			builder.setMessage("If you no longer want to receive points for your Facebook updates," +
					" you must go to Facebook and deauthorize Socio from there.")
		       .setCancelable(false)
		       .setNeutralButton("Ok", new DialogInterface.OnClickListener() {
		           public void onClick(DialogInterface dialog, int id) {
		        	   dismissDialog(CANCEL_FACEBOOK_DIALOG);
		           }
		       });
			dialog = builder.create();
			break;
		}

		return dialog;
	}
	
	/**
	 * Handle message return from threads
	 * @param msg Message returned from thread
	 */
	private void handleBackendThreadMessage(Message msg) {
		switch((BackendThreadMessages)msg.getData().getSerializable("message type")) {
		case SettingsSuccessful:
			displaySettings((ClientUser)msg.obj, true);
			break;
		case TroubleGettingSettings:
			dismissDialog(SETTINGS_PROGRESS_DIALOG);
			showDialog(TROUBLE_GETTING_SETTINGS);
			break;
		case SubmitSuccessful:
			dismissDialog(SETTINGS_PROGRESS_DIALOG);
			showDialog(SUBMIT_SUCCESSFUL_DIALOG);
			break;
		}
	}
	
	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);
		outState.putSerializable("display", display);
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		
		// change font to black if not default string, (for orientation changes)
		if(!nickname.getText().toString().
				equalsIgnoreCase(getResources().getString(R.string.nickname_default_text))) {
			nickname.setTextColor(Color.BLACK);
		}
	}

}
